import binascii
import os
import struct

from udsoncan import Response, services
from udsoncan.connections import PythonIsoTpConnection

from sdk.cfg import tp_funcaddr, tp_physaddr
import serial
import xlrd, os, udsoncan, isotp, sys, binascii


class Socket:
    def __init__(self, Com, Baudrate):
        self.Com = Com
        self.Baudrate = Baudrate
        self.ser = serial.Serial(self.Com, self.Baudrate, timeout=0.5)

    def Open(self):
        self.ser.write(struct.pack('BBBB', 0xA0, 0x01, 0x01, 0xA2))

    def Close(self):
        self.ser.write(struct.pack('BBBB', 0xA0, 0x01, 0x00, 0xA1))

    def loop(self, looptime):
        self.Open()


class Test:
    def __init__(self, client, stack, MyLogger=None):
        self.tp_funcaddr = tp_funcaddr
        self.tp_physaddr = tp_physaddr
        self.udsclient = client
        self.stack = stack
        self.logger = MyLogger
        if stack is not None:
            self.conn = PythonIsoTpConnection(stack)

    def get_xlsx(self, sheet):
        "获取指定Excel数据"
        excel = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'UDSTestcase.xlsx')  # 获取用例文件路径
        file = xlrd.open_workbook(excel)
        list = []
        sheet = file.sheet_by_name(sheet)  # 获得指定sheet数据
        row_value1 = sheet.row_values(0)  # 获取第1行的标题
        nrows = sheet.nrows  # 获取当前sheet行数
        ncols = sheet.ncols  # 获取当前sheet列数
        for i in range(1, nrows):  # 从第2行遍历当前sheet
            row = sheet.row_values(i)  # 获取行数据
            dict = {}  # 创建空字典
            for j in range(0, ncols):  # 遍历sheet列，组成字典
                if row_value1[j] == 'NO.':
                    dict[row_value1[j]] = int(row[j])
                else:
                    dict[row_value1[j]] = row[j]  # 从第一列开始，将每一列的数据与第1行的数据组成一个键值对，形成字典
            list.append(dict)  # 将字典添加list中
        return list

    def uds_request_respond(self, request_command):
        """发送uds请求和接收uds响应"""
        if not isinstance(request_command, str):  # 判断request_command数据类型
            request_command = str(int(request_command))
        requestPdu = binascii.a2b_hex(request_command.replace(' ', ''))  # 处理request_command
        if not self.conn.is_open():
            self.conn.open()  # 打开连接
        try:
            self.conn.specific_send(requestPdu)  # 发送uds请求
        except:
            print("发送请求失败")
        else:
            print('UDS发送请求：%s' % request_command)

        try:
            respPdu = self.conn.specific_wait_frame(timeout=3)  # 接收uds响应
        except:
            print('响应数据失败')
        else:
            res = respPdu.hex().upper()
            respond = ''
            for i in range(len(res)):
                if i % 2 == 0:
                    respond += res[i]
                else:
                    respond += res[i] + ' '
            print('UDS响应结果：%s' % respond)
            return respond.strip()

    def tests_change_address(self, phys, func):
        self.tp_physaddr = phys
        self.tp_funcaddr = func

    def tests_change_client(self, client, stack):
        self.client = client
        self.stack = stack

    def testsServ10(self, mode):
        if mode == 1:
            _modetext = "物理寻址"
        else:
            _modetext = "功能寻址"

        resp = self.udsclient.change_session(1)
        _pass = "Pass" if resp.positive else "Fail"
        self.testlog.insert("insert", "%s下，10服务正响应测试，得到正响应。测试结果：%s\n" % (_modetext, _pass))

        try:
            req = services.DiagnosticSessionControl.make_request(0x07)
            self.conn.send(req.get_payload())
            payload = self.conn.wait_frame(timeout=1)
            resp = Response.from_payload(payload)
            _pass = "Pass" if resp.code == Response.Code.SubFunctionNotSupported else "Fail"
        except:
            _pass = "Fail"
        # print(resp.code)
        self.testlog.insert("insert", "%s下，10服务子功能不支持测试，得到NRC12返信。测试结果：%s\n" % (_modetext, _pass))

        try:
            self.conn.send(b'\x10\x01\x77\x88\x99')
            payload = self.conn.wait_frame(timeout=1)
            resp = Response.from_payload(payload)
            _pass = "Pass" if resp.code == Response.Code.IncorrectMessageLengthOrInvalidFormat else "Fail"
        except:
            _pass = "Fail"
        # print(resp.code)
        self.testlog.insert("insert",
                            "%s下，10服务格式或长度不正确测试，得到NRC13返信。测试结果：%s\n" % (_modetext, _pass))

        self.testlog.insert("insert", "%s下，10服务前置条件不满足测试，得到NRC22返信。测试结果： No Test\n" % (_modetext))

        # resp = self.udsclient.change_session(3)
        try:
            self.conn.send(b'\x10\x02')
            payload = self.conn.wait_frame(timeout=1)
            resp = Response.from_payload(payload)
            _pass = "Pass" if resp.code == Response.Code.SubFunctionNotSupportedInActiveSession else "Fail"
        except:
            _pass = "Fail"
        # print(hex(resp.code))
        self.testlog.insert("insert",
                            "%s下，10服务当前会话下子功能不支持测试，得到NRC$7E返信。测试结果：%s\n" % (_modetext, _pass))

        try:
            self.conn.send(b'\x10\x02')
            payload = self.conn.wait_frame(timeout=1)
            resp = Response.from_payload(payload)
            _pass = "Pass" if resp.code == Response.Code.SubFunctionNotSupportedInActiveSession else "Fail"
        except:
            _pass = "Fail"
        # print(hex(resp.code))
        self.testlog.insert("insert", "%s下，10服务NRC优先级测试。测试结果：No Test\n" % (_modetext))

        try:
            resp1 = self.udsclient.change_session(3)
            resp2 = self.udsclient.change_session(1)
            _pass = "Pass" if resp1.positive and resp2.positive else "Fail"
        except:
            _pass = "Fail"
        self.testlog.insert("insert", "%s下，10服务会话切换测试。测试结果：%s\n" % (_modetext, _pass))

        self.testlog.insert("insert", "%s下，时间超时后会话维持情况测试。测试结果： No Test\n" % (_modetext))

        self.testlog.insert("insert", "%s下，KL15on-off-on会话维持情况测试。测试结果： No Test\n" % (_modetext))

        self.testlog.insert("insert", "%s下，硬件复位后会话维持情况测试。测试结果： No Test\n" % (_modetext))
